package org.redmagic.spring;

import java.util.HashSet;
import java.util.Set;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanDefinitionVisitor;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;

public class MagicPropertyPlaceholderConfigurer implements BeanFactoryPostProcessor, BeanNameAware, BeanFactoryAware {

    private BeanFactory beanFactory;
    private String beanName;
    private BeanDefinitionVisitor visitor;  // TODO: decide how this will get set
    
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        
        if (!beanFactory.equals(this.beanFactory)) {
            parseBeanDefinitions(beanFactory);
        }        
    }
    
    private void parseBeanDefinitions(ConfigurableListableBeanFactory beanFactory) {
        String[] beanDefinitionNames = beanFactory.getBeanDefinitionNames();
        Set<String> unresolvedPlaceholders = findPlaceholders(beanFactory, beanDefinitionNames);
        
        do {
            resolvePlaceholders(unresolvedPlaceholders);
            unresolvedPlaceholders = findPlaceholders(beanFactory, beanDefinitionNames);
        } while (!unresolvedPlaceholders.isEmpty());
    }
    
    private Set<String> findPlaceholders(ConfigurableListableBeanFactory beanFactory, String[] beanDefinitionNames) {
        Set<String> unresolvedPlaceholders = new HashSet<String>();
        
        for (String beanDefinitionName : beanDefinitionNames) {
            unresolvedPlaceholders.addAll(parseBeanDefinition(beanFactory, beanDefinitionName));
        }
        
        return unresolvedPlaceholders;
    }

    private Set<String> parseBeanDefinition(ConfigurableListableBeanFactory beanFactory, String beanDefinitionName) {
        Set<String> unresolvedPlaceholders = new HashSet<String>();
        
        if (!beanDefinitionName.equals(this.beanName)) {
            BeanDefinition beanDefinition = beanFactory.getBeanDefinition(beanDefinitionName);
            unresolvedPlaceholders.addAll(collectPlaceholders(beanDefinition));
        }
        
        return unresolvedPlaceholders;
    }

    private Set<String> collectPlaceholders(BeanDefinition beanDefinition) {

        try {
            // TODO: parse out placeholders
        } catch (Exception e) {
            // TODO: throw some useful error
        }
        
        return null;
    }
    
    private void resolvePlaceholders(Set<String> unresolvedPlaceholders) {
        // TODO:
    }

    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        this.beanFactory = beanFactory;
    }
    
    @Override
    public void setBeanName(String beanName) {
        this.beanName = beanName;
    }
}